import React, { useContext, useState } from 'react';
import FormLayoutContext from '../Context/FormLayoutContext';
import ListContext from '../Context/ListContext';
import NoStyleItemContext from '../Context/NoStyleItemContext';
import Field from '../Field';
import useFrameState from '../hooks/useFrameState';
import type { FormInstance, InternalNamePath } from '../interface';
import type { Meta } from '../interface/FieldEntityType';
import type { FormItemProps } from '../interface/FormItemType';
import ItemHolder from './ItemHolder';

const NAME_SPLIT = '__SPLIT__';

interface MemoInputProps {
  value: any;
  update: any;
  children: React.ReactNode;
  childProps: Record<string, any>;
}

// compare函数 return true 相等，不用重新加载
const MemoInput = React.memo(
  ({ children }: MemoInputProps) => children as JSX.Element,
  (prev, next) =>
    prev.value === next.value &&
    prev.update === next.update &&
    prev.childProps === next.childProps,
);

interface ErrorObj {
  errors: React.ReactNode[];
  warnings: React.ReactNode[];
}

function genEmptyMeta(): Meta {
  return {
    errors: [],
    warnings: [],
    touched: false,
    validating: false,
    validated: false,
    name: [],
  };
}

export function getFieldId(
  namePath: InternalNamePath,
  formName?: string,
): string | undefined {
  if (!namePath.length) return undefined;

  const mergedId = namePath.join('_');

  if (formName) {
    return `${formName}_${mergedId}`;
  }
  return mergedId;
}

const FormItem: React.FC<FormItemProps> = (props) => {
  const {
    name,
    valuePropName = 'value',
    noStyle,
    children,
    required,
    hidden,
    ...restProps
  } = props;
  const listContext = useContext(ListContext);
  const { name: formName } = useContext(FormLayoutContext);
  const isRenderProps = typeof children === 'function';

  const notifyParentMetaChange = useContext(NoStyleItemContext); //嵌套
  const fieldKeyPathRef = React.useRef<InternalNamePath>();

  // ======================== Errors ========================
  // >>>>> Collect sub field errors
  const [subFieldErrors, setSubFieldErrors] = useFrameState<
    Record<string, ErrorObj>
  >({});

  // >>>>> Current field errors
  const [meta, setMeta] = useState<Meta>(() => genEmptyMeta());

  const onMetaChange = (nextMeta: Meta & { destroy?: boolean }) => {
    // listContext不一定存在啊！
    const keyInfo = listContext?.getKey(nextMeta.name); // [0,['name']]
    // console.log('--子级--1.onMetaChange--keyInfo--:', keyInfo);

    // Destroy will reset all the meta
    setMeta(nextMeta.destroy ? genEmptyMeta() : nextMeta);

    // Bump to parent since noStyle
    if (noStyle && notifyParentMetaChange) {
      let currNamepath = nextMeta.name; //meta.name === Field.namePath === ['users',0,'name']
      // console.log('--子级--2.onMetaChange--currNamepath--:', currNamepath);
      if (!nextMeta.destroy) {
        if (keyInfo !== undefined) {
          const [fieldKey, restPath] = keyInfo;
          currNamepath = [fieldKey, ...restPath]; //[0,'name']
          fieldKeyPathRef.current = currNamepath;
          // console.log('--子级--3.onMetaChange--currNamepath--:', currNamepath);
        }
      } else {
        // Use origin cache data
        currNamepath = fieldKeyPathRef.current || currNamepath;
      }
      //子级触发 <Form.Item name="['users',0,'name']" noStyle></Form.Item>
      notifyParentMetaChange(nextMeta, currNamepath);
    }
  };

  /**
   *
   * @param subMeta
   * @param uniqueKeys  [0,'name']
   * @description 父级接收   <Form.Item label="users" >
   */
  const onSubItemMetaChange = (
    subMeta: Meta & { destroy?: boolean },
    uniqueKeys: InternalNamePath,
  ) => {
    setSubFieldErrors((prevSubFieldErrors) => {
      const clone = {
        ...prevSubFieldErrors,
      };

      //subMeta.name === ['users',0,'name']  uniqueKeys  === [0,'name']
      //[...['users',0],...[0,'name']]
      // console.log('--父级--1.subMeta.name--uniqueKeys--:', subMeta.name, uniqueKeys);
      const mergedNamePath = [...subMeta.name.slice(0, -1), ...uniqueKeys];
      const mergedNameKey = mergedNamePath.join(NAME_SPLIT); //user__SPLIT__0__SPLIT__0__SPLIT__name

      if (subMeta.destroy) {
        // Remove
        delete clone[mergedNameKey];
      } else {
        // Update
        clone[mergedNameKey] = subMeta;
      }
      // console.log('--父级--2.clone--：', clone);
      return clone;
    });
  };

  // >>>>> Get merged errors
  const [mergedErrors, mergedWarnings] = React.useMemo(() => {
    const errorList: React.ReactNode[] = [...meta.errors];
    const warningList: React.ReactNode[] = [...meta.warnings];

    Object.values(subFieldErrors).forEach((subFieldError) => {
      errorList.push(...(subFieldError.errors || []));
      warningList.push(...(subFieldError.warnings || []));
    });

    return [errorList, warningList];
  }, [subFieldErrors, meta.errors, meta.warnings]);

  // ======================== Render ========================
  function renderLayout(
    baseChildren: React.ReactNode,
    fieldId?: string,
    isRequired?: boolean,
  ): React.ReactNode {
    if (noStyle && !hidden) {
      return baseChildren;
    }

    return (
      <ItemHolder
        key="row"
        {...restProps}
        fieldId={fieldId}
        required={isRequired}
        errors={mergedErrors}
        warnings={mergedWarnings}
        meta={meta}
        onSubItemMetaChange={onSubItemMetaChange}
      >
        {baseChildren}
      </ItemHolder>
    );
  }

  return (
    <Field
      {...restProps}
      name={name}
      valuePropName={valuePropName}
      onMetaChange={onMetaChange}
    >
      {(control, meta, formInstance) => {
        const { shouldUpdate, dependencies, rules } = restProps;
        // 注： 一旦<Form.Item>.name 存在 onChange ，value、等 会注入到  Field.children/children()的props上 (这里限制不允许使用children())
        // 注： 一旦<Form.Item>.name ！存在 1. onChange,value 不会注入到 Field.children/children()的props上（不会执行Field._getControlled()）

        const mergedName =
          name !== undefined && name !== null && meta ? meta.name : [];
        const fieldId = getFieldId(mergedName, formName);

        const isRequired =
          required !== undefined
            ? required
            : !!(
                rules &&
                rules.some((rule) => {
                  if (
                    rule &&
                    typeof rule === 'object' &&
                    rule.required &&
                    !rule.warningOnly
                  ) {
                    return true;
                  }
                  if (typeof rule === 'function') {
                    const ruleEntity = rule(formInstance);
                    return (
                      ruleEntity &&
                      ruleEntity.required &&
                      !ruleEntity.warningOnly
                    );
                  }
                  return false;
                })
              );

        let childNode: React.ReactNode = null;
        if (Array.isArray(children)) {
          throw new Error('当前FormItem.children必须是单节点');
        }

        if (name !== undefined && name !== null) {
          //name存在
          if (isRenderProps) {
            throw new Error(
              'FormItem.name 存在时，FormItem.children禁止为function',
            );
          } else {
            if (!React.isValidElement(children)) return children;
            if (fieldId) {
              control.id = fieldId;
            }
            childNode = (
              <MemoInput
                value={control[valuePropName]}
                update={children}
                childProps={control}
              >
                {React.cloneElement(children, { ...control })}
              </MemoInput>
            );
          }
        } else {
          if (shouldUpdate && dependencies) {
            throw new Error(
              'shouldUpdate和dependencies功能有重叠，请勿同时在同一个FormItem上使用',
            );
          } else if ((shouldUpdate || dependencies) && !isRenderProps) {
            throw new Error(
              '使用shouldUpdate/dependencies时FormItem.children必须是function',
            );
          } else if (isRenderProps) {
            childNode = (
              children as (formInstance?: FormInstance) => React.ReactNode
            )(formInstance);
          } else {
            childNode = children;
          }
        }
        return renderLayout(childNode, fieldId, isRequired);
      }}
    </Field>
  );
};

export default FormItem;
